home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SPACE 1
/
SPACE - Library 1 - Volume 1.iso
/
program
/
355
/
source
/
ifsdemo
/
ifs.mod
< prev
next >
Wrap
Text File
|
1990-02-02
|
13KB
|
435 lines
MODULE IFS;
(* This is a demonstration of Iterated Function Systems based on an article
entitled 'A Better Way to Compress Images' by Michael F. Barnsley and
Alan D. Sloan, Byte Magazine, Vol. 13, No. 1. - Mike Long 1/15/88 *)
FROM SYSTEM IMPORT ADR, ADDRESS;
FROM AESevents IMPORT EvntMulti;
FROM AESGraphics IMPORT GrafGrowbox,
GrafShrinkbox;
FROM AESMenu IMPORT MenuBar,
MenuTnormal;
FROM AESResource IMPORT RsrcGAddr;
FROM AESWindows IMPORT WindGet,
WindUpdate,
WindCreate,
WindOpen,
WindClose,
WindDelete,
WindSet;
FROM BitStuff IMPORT SetBit,
TestBit;
FROM GEMConstants IMPORT WFWORKXYWH,
BEGUPDATE,
ENDUPDATE,
MUKEYBD,
MUMESAG,
MNSELECTED,
NAME,
WFNAME;
FROM GEMProcs IMPORT GEMInit,
GEMTerm,
GEMRec,
GEMState,
ShowMouse,
HideMouse,
DoDialog,
AddrToInts;
FROM VDIControl IMPORT VswrMode;
FROM VDIOutput IMPORT VBar,
VPmarker;
FROM VDISettings IMPORT VsfInterior,
VsfStyle,
VsfColor,
VsmType,
VsmHeight,
VsmColor;
FROM XBIOSMisc IMPORT random;
CONST MAINMENU = 0; (* menu tree *)
INFO = 8; (* STRING in tree MAINMENU *)
QUIT = 17; (* STRING in tree MAINMENU *)
TRIANGLE = 19; (* STRING in tree MAINMENU *)
FERN = 20; (* STRING in tree MAINMENU *)
TREE = 21; (* STRING in tree MAINMENU *)
SQUARE = 22; (* STRING in tree MAINMENU *)
INFOBOX = 1; (* form/dialog *)
OK = 5; (* BUTTON in tree INFOBOX *)
(* A DataRec holds the data for one image. Notice that, even though the images
are fairly complex, the data for each image is only 32 REALs. Fractals are
wonderful things! *)
TYPE DataRec = RECORD
a,b,c,d,e,f,p : ARRAY [1..4] OF REAL;
xs,ys,xo,yo : REAL;
END;
VAR xdesk, ydesk, wdesk, hdesk : INTEGER;
dummy : INTEGER;
windopen : BOOLEAN; (* Is a window open? *)
windhandle : INTEGER; (* This is it's handle *)
triangle : DataRec;
fern : DataRec;
tree : DataRec;
square : DataRec;
PROCEDURE InitData();
(* As you might guess, this procedure plugs the proper values into the image
data records. Fields a, b, c, d, e, and f are the fractal data. Field p is
the probablity that any particular set of data will be used. Fields xs and
ys are the scaling factors that scale each image to the screen. Fields xo
and yo are offsets that center each image on the screen. *)
BEGIN
triangle.a[1] := 0.5;
triangle.b[1] := 0.0;
triangle.c[1] := 0.0;
triangle.d[1] := 0.5;
triangle.e[1] := 0.5;
triangle.f[1] := 0.5;
triangle.p[1] := 0.34;
triangle.a[2] := 0.5;
triangle.b[2] := 0.0;
triangle.c[2] := 0.0;
triangle.d[2] := 0.5;
triangle.e[2] := 1.0;
triangle.f[2] := 0.0;
triangle.p[2] := 0.67;
triangle.a[3] := 0.5;
triangle.b[3] := 0.0;
triangle.c[3] := 0.0;
triangle.d[3] := 0.5;
triangle.e[3] := 0.0;
triangle.f[3] := 0.0;
triangle.p[3] := 1.0;
triangle.a[4] := 0.0;
triangle.b[4] := 0.0;
triangle.c[4] := 0.0;
triangle.d[4] := 0.0;
triangle.e[4] := 0.0;
triangle.f[4] := 0.0;
triangle.p[4] := 1.0;
triangle.xs := 300.0;
triangle.ys := 300.0;
triangle.xo := 20.0;
triangle.yo := 36.0;
fern.a[1] := 0.85;
fern.b[1] := 0.04;
fern.c[1] := -0.04;
fern.d[1] := 0.85;
fern.e[1] := 0.0;
fern.f[1] := 1.6;
fern.p[1] := 0.85;
fern.a[2] := -0.15;
fern.b[2] := 0.28;
fern.c[2] := 0.26;
fern.d[2] := 0.24;
fern.e[2] := 0.0;
fern.f[2] := 0.44;
fern.p[2] := 0.92;
fern.a[3] := 0.2;
fern.b[3] := -0.26;
fern.c[3] := 0.23;
fern.d[3] := 0.22;
fern.e[3] := 0.0;
fern.f[3] := 1.6;
fern.p[3] := 0.99;
fern.a[4] := 0.0;
fern.b[4] := 0.0;
fern.c[4] := 0.0;
fern.d[4] := 0.16;
fern.e[4] := 0.0;
fern.f[4] := 0.0;
fern.p[4] := 1.0;
fern.xs := 35.0;
fern.ys := 35.0;
fern.xo := 312.0;
fern.yo := 8.0;
tree.a[1] := 0.42;
tree.b[1] := 0.42;
tree.c[1] := -0.42;
tree.d[1] := 0.42;
tree.e[1] := 0.0;
tree.f[1] := 0.2;
tree.p[1] := 0.4;
tree.a[2] := 0.42;
tree.b[2] := -0.42;
tree.c[2] := 0.42;
tree.d[2] := 0.42;
tree.e[2] := 0.0;
tree.f[2] := 0.2;
tree.p[2] := 0.8;
tree.a[3] := 0.1;
tree.b[3] := 0.0;
tree.c[3] := 0.0;
tree.d[3] := 0.1;
tree.e[3] := 0.0;
tree.f[3] := 0.2;
tree.p[3] := 0.95;
tree.a[4] := 0.0;
tree.b[4] := 0.0;
tree.c[4] := 0.0;
tree.d[4] := 0.5;
tree.e[4] := 0.0;
tree.f[4] := 0.0;
tree.p[4] := 1.0;
tree.xs := 800.0;
tree.ys := 800.0;
tree.xo := 320.0;
tree.yo := 0.0;
square.a[1] := 0.5;
square.b[1] := 0.0;
square.c[1] := 0.0;
square.d[1] := 0.5;
square.e[1] := 0.5;
square.f[1] := 0.5;
square.p[1] := 0.25;
square.a[2] := 0.5;
square.b[2] := 0.0;
square.c[2] := 0.0;
square.d[2] := 0.5;
square.e[2] := 0.0;
square.f[2] := 0.5;
square.p[2] := 0.50;
square.a[3] := 0.5;
square.b[3] := 0.0;
square.c[3] := 0.0;
square.d[3] := 0.5;
square.e[3] := 0.5;
square.f[3] := 0.0;
square.p[3] := 0.75;
square.a[4] := 0.5;
square.b[4] := 0.0;
square.c[4] := 0.0;
square.d[4] := 0.5;
square.e[4] := 0.0;
square.f[4] := 0.0;
square.p[4] := 1.0;
square.xs := 300.0;
square.ys := 300.0;
square.xo := 174.0;
square.yo := 32.0;
END InitData;
PROCEDURE Initialize();
(* This one initializes the program. It initializes the data and paints the
screen gray. *)
VAR temp : ARRAY [0..3] OF INTEGER;
BEGIN
windopen := FALSE; (* no window opened yet *)
InitData;
dummy := WindGet(0,WFWORKXYWH,xdesk,ydesk,wdesk,hdesk);
dummy := VsfInterior(GEMState.handle,2);
dummy := VsfStyle(GEMState.handle,4);
dummy := VsfColor(GEMState.handle,1);
temp[0] := xdesk;
temp[1] := ydesk;
temp[2] := xdesk + wdesk - 1;
temp[3] := ydesk + hdesk - 1;
HideMouse;
VBar(GEMState.handle,temp);
ShowMouse;
END Initialize;
PROCEDURE CloseWindow();
(* Closes the currently open window and sets windopen to FALSE. The window
is deleted after it is closed. *)
BEGIN
dummy := WindClose(windhandle);
dummy := GrafShrinkbox((xdesk + (wdesk DIV 2)),(ydesk + (hdesk DIV 2)),
GEMState.wbox,GEMState.hbox,xdesk,ydesk,wdesk,hdesk);
dummy := WindDelete(windhandle);
windopen := FALSE;
END CloseWindow;
PROCEDURE OpenWindow(name : ADDRESS);
(* Opens a window with only a title bar. When it takes 4 minutes to redraw
the screen we don't want sizers, etc. *)
VAR features : INTEGER;
i1,i2 : INTEGER;
BEGIN
features := 0;
SetBit(NAME,features);
windhandle := WindCreate(features,xdesk,ydesk,wdesk,hdesk);
AddrToInts(name,i1,i2);
dummy := WindSet(windhandle,WFNAME,i1,i2,0,0);
dummy := GrafGrowbox((xdesk + (wdesk DIV 2)),(ydesk + (hdesk DIV 2)),
GEMState.wbox,GEMState.hbox,xdesk,ydesk,wdesk,hdesk);
dummy := WindOpen(windhandle,xdesk,ydesk,wdesk,hdesk);
windopen := TRUE;
END OpenWindow;
PROCEDURE Random() : REAL;
(* Returns a random REAL between 0 and 1 *)
VAR l : LONGINT;
f : REAL;
BEGIN
l := random();
l := l MOD 30000D;
f := FLOAT(l);
f := f / 30000.0;
RETURN(f);
END Random;
PROCEDURE Decode(data : DataRec;
name : ADDRESS);
(* This is the procedure that does all the work. It is based on a small basic
program that was included in the above cited article. For an explanation
of how it works, see the article. They explain it better than I could. *)
VAR wx,wy,ww,wh : INTEGER;
temp : ARRAY [0..3] OF INTEGER;
where : ARRAY [0..1] OF INTEGER;
x,y : REAL;
newx,newy : REAL;
pk : REAL;
k : INTEGER;
i : CARDINAL;
BEGIN
HideMouse;
IF windopen THEN
CloseWindow;
END;
OpenWindow(name);
dummy := WindGet(windhandle,WFWORKXYWH,wx,wy,ww,wh);
dummy := VsfInterior(GEMState.handle,2);
dummy := VsfStyle(GEMState.handle,8);
dummy := VsfColor(GEMState.handle,0);
dummy := VswrMode(GEMState.handle,1);
temp[0] := wx;
temp[1] := wy;
temp[2] := wx + ww - 1;
temp[3] := wy + wh - 1;
VBar(GEMState.handle,temp); (* Clear the window *)
dummy := VsmType(GEMState.handle,1);
dummy := VsmHeight(GEMState.handle,1);
dummy := VsmColor(GEMState.handle,1);
x := 0.0;
y := 0.0;
FOR i := 1 TO 65000 DO
pk := Random();
IF pk <= data.p[1] THEN
k := 1;
ELSIF pk <= data.p[2] THEN
k := 2;
ELSIF pk <= data.p[3] THEN
k := 3;
ELSE
k := 4;
END;
newx := data.a[k] * x + data.b[k] * y + data.e[k];
newy := data.c[k] * x + data.d[k] * y + data.f[k];
x := newx;
y := newy;
where[0] := TRUNC(x * data.xs + data.xo + 0.5);
where[1] := TRUNC(y * data.ys + data.yo + 0.5);
where[1] := 400 - where[1];
IF i > 10 THEN
VPmarker(windhandle,1,where);
END;
END;
ShowMouse;
END Decode;
PROCEDURE DoMenu();
(* This procedure contains the event loop that is the driver for the program.
Notice that redraw messages are not handled. It takes 4 minutes to redraw
the screen, and I didn't want to mess with buffering the data somewhere,
so I don't do redraws. One effect of this decision is that the INFO
box is only drawn at program start, before any windows are opened. In
addition, any accessories opened on top of a window will destroy the
underlying data. *)
VAR flags : INTEGER;
menuaddr : ADDRESS;
event : INTEGER;
endprogram : BOOLEAN;
keycode : INTEGER;
messagebuffer : ARRAY [0..7] OF INTEGER;
BEGIN
dummy := RsrcGAddr(0,MAINMENU,menuaddr);
dummy := MenuBar(menuaddr,1);
DoDialog(INFOBOX);
endprogram := FALSE;
flags := 0;
SetBit(MUMESAG,flags);
SetBit(MUKEYBD,flags);
REPEAT
event := EvntMulti(flags,
0,0,0,
0,0,0,0,0,
0,0,0,0,0,
ADR(messagebuffer),
0,0,
dummy,dummy,dummy,
dummy,keycode,dummy);
dummy := WindUpdate(BEGUPDATE);
IF TestBit(MUMESAG,event) THEN
CASE messagebuffer[0] OF
MNSELECTED : CASE messagebuffer[4] OF
QUIT : endprogram := TRUE; |
INFO : ; |
TRIANGLE : Decode(triangle,
ADR(' Sierpinski Triangle ')); |
FERN : Decode(fern,
ADR(' Fern ')); |
TREE : Decode(tree,
ADR(' Fractal Tree ')); |
SQUARE : Decode(square,
ADR(' Square ')); |
END;
dummy := MenuTnormal(menuaddr,messagebuffer[3],1);
ELSE
;
END;
END;
IF TestBit(MUKEYBD,event) THEN
; (* We could add some hotkeys here later. *)
END;
dummy := MenuBar(menuaddr,1);
dummy := WindUpdate(ENDUPDATE);
UNTIL endprogram;
IF windopen THEN
CloseWindow;
END;
dummy := MenuBar(menuaddr,0);
END DoMenu;
BEGIN
IF GEMInit(ADR('ifs.rsc')) THEN
Initialize;
DoMenu;
END;
GEMTerm;
END IFS.